/*
 * @Date: 2023-04-07 10:44:31
 * @LastEditTime: 2023-09-21 15:27:18

 * 介绍:
 */

import dayjs from "dayjs";
import { Ref } from "vue";
import PubSub from "pubsub-js";

const intervalRecord: AnyObject<intervalRecordItem | undefined> = {};
interface intervalRecordItem {
  interval: NodeJS.Timeout | void;
  callbacks: Function[];
}

/**
 * * 使用循环定时器
 * @param callback 回调
 * @param time 间隔毫秒
 * @param cfg 初始化配置
 * @returns
 */
export function useInterval(
  callback: Function,
  time: number = 1000,
  cfg?: HookConfig
) {
  function intervalPublish() {
    intervalRecord[time.toString()]!.callbacks.forEach((f) => {
      if (typeof f === "function") f();
    });
  }
  function open() {
    if (!intervalRecord[time.toString()]) {
      console.log(`开启间隔为${time}的循环定时器`);
      intervalRecord[time.toString()] = {
        interval: setInterval(intervalPublish, time),
        callbacks: [],
      };
    }
    intervalRecord[time.toString()]!.callbacks.push(callback);
  }
  function close() {
    const intervalRecordItem = intervalRecord[time?.toString()];
    if (!intervalRecordItem) return;
    const callbacks = intervalRecordItem.callbacks;
    for (const key in callbacks) {
      const i = Number(key);
      if (callbacks[i] === callback) callbacks.splice(i, 1);
    }
    if (callbacks.length <= 0) {
      if (intervalRecordItem.interval) {
        console.log(`清除间隔为${time}的循环定时器`);
        clearInterval(intervalRecordItem.interval);
      }
      intervalRecord[time?.toString()] = undefined;
    }
  }
  if (cfg?.setupOpen !== false) open();
  if (cfg?.activatedOpen !== false) {
    onActivated(() => {
      open();
    });
  }
  if (cfg?.unmountedClear !== false) onUnmounted(close);
  if (cfg?.beforeRouteLeaveClear !== false) onBeforeRouteLeave(close);

  return { close, open };
}
interface HookConfig {
  setupOpen?: boolean;
  activatedOpen?: boolean;
  unmountedClear?: boolean;
  beforeRouteLeaveClear?: boolean;
}

export function useCurrentDate(time = 1000, cfg?: HookConfig) {
  /**当前时间 */
  const currentDate = ref(dayjs());
  function setCurrentDate() {
    currentDate.value = dayjs();
  }
  const { close, open } = useInterval(setCurrentDate, time, cfg);
  return { currentDate, close, open };
}
/**
 * * 缓存元素滚动条
 * @param domRef ref元素
 * @returns
 */
export function useScrollTop(
  domRef: Ref<HTMLElement | undefined>,
  cfg?: ScrollTopCfg
) {
  let scrollTop: number;
  onDeactivated(getScrollTop);
  onActivated(setScrollTop);
  function getScrollTop() {
    return (scrollTop = domRef.value?.scrollTop || 0);
  }
  function setScrollTop(top = scrollTop, _cfg?: ScrollTopCfg) {
    if (!domRef.value) return;
    domRef.value.scroll({
      top,
      behavior: _cfg?.behavior || cfg?.behavior || "auto",
    });
  }
  return { getScrollTop, setScrollTop };
}
export interface ScrollTopCfg {
  behavior?: ScrollBehavior;
}

/**
 * 使用pubsub
 * @returns
 */
export function useSubscribe() {
  const map = new Map<string | symbol, SubscriptionListener>();
  onUnmounted(unsubscribeAll);
  return { subscribe, unsubscribe, unsubscribeAll };
  type SubscriptionListener = (message: string, data?: any) => void;
  function subscribe(message: string | symbol, func: SubscriptionListener) {
    PubSub.subscribe(message, func);
    map.set(message, func);
  }
  function unsubscribe(tokenOrFunction: string | SubscriptionListener) {
    PubSub.unsubscribe(tokenOrFunction);
    if (typeof tokenOrFunction === "string") map.delete(tokenOrFunction);
    for (const value of map) {
      if (value[1] === tokenOrFunction) return map.delete(value[0]);
    }
  }
  function unsubscribeAll() {
    map.forEach((v) => PubSub.unsubscribe(v));
    map.clear();
  }
}
